// Copyright Epic Games, Inc. All Rights Reserved.

#include "GameplayAbilityTargetActor_Interact.h"
#include "Async/TaskGraphInterfaces.h"
#include "DrawDebugHelpers.h"
#include "CollisionQueryParams.h"
#include "GameFramework/LightWeightInstanceSubsystem.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(GameplayAbilityTargetActor_Interact)

// 构造函数
AGameplayAbilityTargetActor_Interact::AGameplayAbilityTargetActor_Interact(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
}

/**
 * 执行追踪以检测可交互对象
 * @param InSourceActor 发起追踪的Actor
 * @return 返回追踪命中的结果
 */
FHitResult AGameplayAbilityTargetActor_Interact::PerformTrace(AActor* InSourceActor)
{
	bool bTraceComplex = false; // 是否进行复杂碰撞检测
	TArray<AActor*> ActorsToIgnore; // 需要忽略的Actor列表

	ActorsToIgnore.Add(InSourceActor); // 将源Actor加入忽略列表

	FCollisionQueryParams Params(SCENE_QUERY_STAT(AGameplayAbilityTargetActor_SingleLineTrace), bTraceComplex); // 碰撞查询参数
	Params.bReturnPhysicalMaterial = true; // 返回物理材质
	Params.AddIgnoredActors(ActorsToIgnore); // 添加忽略的Actor

	FVector TraceStart = StartLocation.GetTargetingTransform().GetLocation(); // 追踪起始位置
	FVector TraceEnd; // 追踪结束位置
	AimWithPlayerController(InSourceActor, Params, TraceStart, TraceEnd);		// 使用玩家控制器进行瞄准，确定追踪方向（仅在服务器和发起客户端有效）

	// ------------------------------------------------------

	FHitResult ReturnHitResult; // 返回的命中结果
	LineTraceWithFilter(ReturnHitResult, InSourceActor->GetWorld(), Filter, TraceStart, TraceEnd, TraceProfile.Name, Params); // 使用过滤条件进行线性追踪
	// 如果没有命中任何物体，默认使用追踪线的终点
	if (!ReturnHitResult.bBlockingHit)
	{
		ReturnHitResult.Location = TraceEnd; // 设置位置为追踪终点
	}
	if (AGameplayAbilityWorldReticle* LocalReticleActor = ReticleActor.Get()) // 获取当前的光标指示器Actor
	{
		const bool bHitActor = (ReturnHitResult.bBlockingHit && (ReturnHitResult.HitObjectHandle.IsValid())); // 判断是否命中有效Actor
		const FVector ReticleLocation = (bHitActor && LocalReticleActor->bSnapToTargetedActor) ? FLightWeightInstanceSubsystem::Get().GetLocation(ReturnHitResult.HitObjectHandle) : ReturnHitResult.Location; // 计算光标位置：如果命中Actor且需要吸附，则使用Actor位置，否则使用命中点

		LocalReticleActor->SetActorLocation(ReticleLocation); // 设置光标Actor位置
		LocalReticleActor->SetIsTargetAnActor(bHitActor); // 设置目标是否为Actor
	}

#if ENABLE_DRAW_DEBUG
	if (bDebug) // 如果启用调试绘制
	{
		DrawDebugLine(GetWorld(), TraceStart, TraceEnd, FColor::Green); // 绘制调试线（绿色）
		DrawDebugSphere(GetWorld(), TraceEnd, 100.0f, 16, FColor::Green); // 在追踪终点绘制调试球体（绿色）
	}
#endif // ENABLE_DRAW_DEBUG
	return ReturnHitResult; // 返回命中结果
}